package com.tuanzi.loan.web.configuration;

import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

import javax.annotation.PostConstruct;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;

import com.google.common.collect.Lists;
import com.tuanzi.loan.business.entity.CurrentUser;
import com.tuanzi.loan.business.entity.system.Role;
import com.tuanzi.loan.business.entity.system.SystemUser;
import com.tuanzi.loan.business.service.system.RoleService;
import com.tuanzi.loan.core.exception.SystemException;
import com.tuanzi.loan.web.bean.CurrentUserBean;
import com.tuanzi.loan.workflow.common.EndEventType;
import com.tuanzi.loan.workflow.entity.Opinion;
import com.tuanzi.loan.workflow.service.OpinionService;
import com.tuanzi.loan.workflow.service.WorkflowManagerService;
import com.tuanzi.loan.workflow.service.WorkflowProcessorService;
import com.tuanzi.loan.workflow.vo.ActivityResponse;
import com.tuanzi.loan.workflow.vo.AssigneeResponse;
import com.tuanzi.loan.workflow.vo.TaskResponse;
import com.tuanzi.loan.workflow.vo.request.CommitTaskRequest;

import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;

/**
 * @author Ray 2018/01/23
 */
@Slf4j
public abstract class JSFWorkflowBean<T> extends JSFInfoBean<T> {

	private static final long serialVersionUID = 8455222880636760300L;
	@Autowired
	private RoleService roleService;
	@Autowired
	private CurrentUserBean currentUserBean;
	@Autowired
	protected WorkflowManagerService workflowManagerService;
	@Autowired
	protected WorkflowProcessorService workflowProcessorService;
	@Autowired
	protected OpinionService opinionService;

	private ActivityResponse cancelEndEventActivity;
	private ActivityResponse rejectEndEventActivity;
	private ActivityResponse passEndEventActivity;
	private List<ActivityResponse> nextActivities;
	@Getter
	protected TaskResponse task;
	@Getter
	protected List<Opinion> opinions;
	@Getter
	@Setter
	protected Opinion opinion;

	@Getter
	private boolean passEnd;
	@Getter
	private boolean rejectEnd;
	@Getter
	private boolean cancelEnd;
	@Getter
	private TaskResponse lastTask;
	@Getter
	private ActivityResponse currentActivity;
	@Getter
	private List<ActivityResponse> nextActivitiesWithoutEndEvent;
	@Getter
	private List<SystemUser> nextAsigneeSystemUser;
	@Getter
	@Setter
	private String selectedNextActivityId;
	@Getter
	@Setter
	private String selectedNextAssignee;

	@PostConstruct
	private void init() {

		String taskId = getParamFromRequest("taskId");

		if (StringUtils.isNotBlank(taskId)) {
			initWorkflowInfo(taskId);
		}
	}

	private void initWorkflowInfo(String taskId) {
		task = workflowProcessorService.findTask(taskId);

		if (task == null) {
			task = workflowProcessorService.findHistoricalTask(taskId);
			opinion = opinionService.findByProcDefIdAndTaskId(task.getProcInstId(), task.getId());
		} else {
			initOpinion();
		}

		opinions = opinionService.findAllByProcInstId(task.getProcInstId());

		lastTask = workflowProcessorService.findLastFinishedTask(task.getProcInstId(), task.getId(), task.getCreateTime());
		currentActivity = workflowProcessorService.findActivity(task.getProcInstId(), task.getTaskDefinitionKey());
		nextActivities = workflowProcessorService.findNextActivity(task.getProcInstId(), task.getTaskDefinitionKey());
		nextActivitiesWithoutEndEvent = Lists.newArrayList();

		List<AssigneeResponse> nextActivityAssigneeResponses = Lists.newArrayList();

		for (ActivityResponse nextActivityResponse : nextActivities) {
			EndEventType endEventType = workflowProcessorService.getEndEventType(nextActivityResponse);

			if (endEventType != null) {

				switch (endEventType) {
				case PASS_END_EVENT:
					passEnd = true;
					passEndEventActivity = nextActivityResponse;
					break;
				case REJECT_END_EVENT:
					rejectEnd = true;
					rejectEndEventActivity = nextActivityResponse;
					break;
				case CANCEL_END_EVENT:
					cancelEnd = true;
					cancelEndEventActivity = nextActivityResponse;
					break;
				default:
					log.warn("找不到节点结束类型, 错误参数 : {} ", nextActivityResponse.getActivityId());
					throw new SystemException("找不到节点结束类型");
				}
				continue;
			}

			nextActivitiesWithoutEndEvent.add(nextActivityResponse);
			if (CollectionUtils.isNotEmpty(nextActivityResponse.getAssignees())) {
				nextActivityAssigneeResponses.addAll(nextActivityResponse.getAssignees());
			}
		}

		nextAsigneeSystemUser = workflowManagerService.findSystemUserByAssignees(nextActivityAssigneeResponses);

		currentUserBean.refreshHeader();
		update(":topForm:undoWorkCount");
	}

	private void initOpinion() {
		opinion = new Opinion();
		opinion.setProcInstId(task.getProcInstId());
		opinion.setCreateTime(new Date());
		opinion.setTaskId(task.getId());
		opinion.setAccount(CurrentUser.get().getAccount());
		opinion.setUserName(CurrentUser.get().getName());
		opinion.setTaskName(task.getTaskName());
		opinion.setRoleName(roleService.findAllByUserId(CurrentUser.get().getUserId()).stream().map(Role::getName).sorted().collect(Collectors.joining(",")));
	}

	public void onPrepareCommitAndShowNextActivityInfoDialog() {
		if (onPrepareCommit()) {
			execute("PF('workflowApproveDialogWidgetVar').show();");
		}
	}

	public boolean onPrepareCommit() {
		try {
			onSave();
			validate();
			if (StringUtils.isBlank(opinion.getOpinion())) {
				addErrorMessage("请输入审批意见");
				return false;
			}
			return true;
		} catch (Exception e) {
			log.error(e.getMessage(), e);
			addErrorMessage(e.getMessage());
			return false;
		}
	}

	public String onApprove() {
		if (StringUtils.isBlank(selectedNextActivityId)) {
			addErrorMessage("请选择后续环节");
			return null;
		}

		if (StringUtils.isBlank(selectedNextAssignee)) {
			addErrorMessage("请选择后续处理人");
			return null;
		}
		workflowProcessorService.approve(structureCommitTaskRequest(selectedNextActivityId, selectedNextAssignee));
		return redirect("/views/workbench.xhtml");
	}

	public String onReject() {
		workflowProcessorService.reject(structureCommitTaskRequest(rejectEndEventActivity.getActivityId(), null));
		return redirect("/views/workbench.xhtml");
	}

	public String onCancel() {
		workflowProcessorService.cancel(structureCommitTaskRequest(cancelEndEventActivity.getActivityId(), null));
		return redirect("/views/workbench.xhtml");
	}

	public String onPass() {
		if (onPrepareCommit()) {
			workflowProcessorService.pass(structureCommitTaskRequest(passEndEventActivity.getActivityId(), null));
			return redirect("/views/workbench.xhtml");
		}
		return null;
	}

	public String onBack() {
		workflowProcessorService.back(task.getProcInstId(), task.getId());
		return redirect("/views/workbench.xhtml");
	}

	private CommitTaskRequest structureCommitTaskRequest(String nextActivityId, String nextAssignee) {
		CommitTaskRequest request = new CommitTaskRequest();
		request.setProcInstId(task.getProcInstId());
		request.setProcDefId(task.getProcDefId());
		request.setTaskDefinitionKey(task.getTaskDefinitionKey());
		request.setTaskId(task.getId());
		request.setNextActivityId(nextActivityId);
		request.setNextAssigneeAccount(nextAssignee);
		request.setOpinion(opinion);
		return request;
	}

	public abstract void onSave() throws Exception;

	public abstract void validate() throws Exception;

}
